package com.tom.service.impl;

import com.alibaba.fastjson.JSON;
import com.tom.dto.ArticleOperateParamDTO;
import com.tom.dto.ArticleParamDTO;
import com.tom.dto.ArticleContentDTO;
import com.tom.entity.ArticleJSON;
import com.tom.mapper.bwarticle.ArticleMapper;
import com.tom.mapper.opencms.TomArticleMapper;
import com.tom.service.ArticleRemoteService;
import com.tom.service.CMSArticleApi;
import jodd.http.HttpRequest;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import com.tom.constant.ArticleEnum;
import com.tom.constant.SystemConstant;
import com.tom.dto.MessageRes;
import com.tom.config.Channel;
import com.tom.exception.BizException;
import com.tom.exception.CommonError;
import com.tom.service.IArticleService;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Service
@Slf4j
public class ArticleRemoteServiceImpl implements ArticleRemoteService {


    @Autowired
    private IArticleService articleService;

    @Autowired
    private TomArticleMapper tomArticleMapper;

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private CMSArticleApi articleApi;

    @Value("${bw-article.opencms-delete-article}")
    private String opencmsDeleteApi;

    @Autowired
    private Channel channel;

    @Value("${bw-article.Directoryprefix}")
    private String prefix;

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public String operate(ArticleOperateParamDTO articleParamDTO) {
        // 1. 参数检验
        if (articleParamDTO == null) {
            throw new BizException(CommonError.PARAM_INVALID);
        }
        // 1.1 校验operate
        if (articleParamDTO.getOperation() == null) {
            throw new BizException(CommonError.OPERATE_PARAM_INVALID);
        }
        // 1.2 校验articleParams
        if (articleParamDTO.getArticleParams() == null || articleParamDTO.getArticleParams().isEmpty()) {
            throw new BizException(CommonError.ARTICLE_PARAM_INVALID);
        }

        String siteNo = "10";
        List<ArticleParamDTO> articleParams = articleParamDTO.getArticleParams();
        switch (articleParamDTO.getOperation()) {
            case INSERT:
                // 2.1 调用新增方法逻辑
                articleParams.forEach(item -> {
                    getArticleContent(item.getType(),
                            item.getArticleNo(),
                            siteNo,
                            "2");
                });
                break;
            case UPDATE:
                // 2.2 调用更新方法逻辑
                articleParams.forEach(item -> {
                    getArticleContent(item.getType(),
                            item.getArticleNo(),
                            siteNo,
                            "1");
                });
                break;
            case DELETE:
                // 2.3 调用删除方法逻辑
                List<MessageRes> messageResList = new ArrayList<>();
                articleParams.forEach(item -> {
                    MessageRes messageResult = remove(item.getType(), item.getArticleNo());
                    log.error("删除文章类型: {} 文章编号: {} 出现问题: {}", item.getType(), item.getArticleNo(), messageResult);
                    messageResList.add(messageResult);
                });
                if (messageResList != null && !messageResList.isEmpty()) {
                    StringBuilder messageInfo = new StringBuilder();
                    messageResList.forEach(item -> messageInfo.append(StringUtils.join(item.getMsg())));
                    throw new BizException(SystemConstant.DELETE_FAIL_CODE, messageInfo.toString());
                }
                break;
            default:
//                throw new BizException(CommonError.PARAM_INVALID);
                break;
        }
        return null;
    }

    /**
     * 删除系统文章
     *
     * @param type
     * @param articleNo
     */
    private MessageRes remove(String type, String articleNo) {
        // 1. 根据文章类型和文章编号查找到文章路径
        String accessParameters = "Type=" + type + "&ArticleNo=" + articleNo;
        MessageRes messageRes = null;
        String articlePath = tomArticleMapper.selectAccessParameter(accessParameters);

        // 2. 调用opencms系统内部接口删除文章
        if (articlePath != null) {
            messageRes = removeOpencms(articlePath);
        }

        // 3. 删除文章记录表(article)
        int rows = articleMapper.delete("SiteNo=10&" + accessParameters);
        if (rows < 1) {
            String message = "bwarticle中article表(爬虫记录表)不存在导致删除失败，文章编号:" + articleNo +
                    "文章类型(type): " + type +
                    "，请联系工程师查询原因";
            if (messageRes == null) {
                messageRes = MessageRes.success();
            }
            messageRes.addMsg(message);
        }
        return messageRes;
    }

    /**
     * 根据文章路径从opencms删除文章
     *
     * @param articlePath
     * @return
     */
    private MessageRes removeOpencms(String articlePath) {
        HttpRequest httpRequest = null;
        MessageRes messageRes = MessageRes.success();
        try {
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));

            String requestApi = opencmsDeleteApi + "?articleUrl=" + articlePath;

            HttpEntity<String> httpEntity = new HttpEntity<>(null, httpHeaders);
            ResponseEntity<String> response = restTemplate.postForEntity(requestApi, httpEntity, String.class);
            log.info("opencms删除文章:{} ;文章路径:{}", httpRequest, articlePath);
            String messageContent = response.getBody();
            HashMap<Integer, List<String>> messageResHashMap = JSON.parseObject(messageContent, HashMap.class);
            if (MessageRes.success_code.equals(messageResHashMap.keySet().iterator().next())) {
                log.debug("opencms删除文章返回结果： {}", messageContent);
                return null;
            }
            log.error("opencms删除文章返回结果异常： {}", messageContent);
            return messageRes;
        } catch (Exception e) {
            log.error("opencms删除文章错误:{}", httpRequest, e);
            messageRes.addMsg("bw-article-api项目调用opencms出现异常，请检查opencms是否正常或者网络是否正常");
            return messageRes;
        }
    }


    /**
     * 获取文章详情
     *
     * @param DataTab    类型
     * @param ID         文章ID
     * @param siteNo     10，16，17
     * @param provenance 状态（1-更新；2-新增）
     * @return 返回消息
     */
    @Override
    public synchronized String getArticleContent(String DataTab, String ID, String siteNo, String provenance) {
        String accessParameters = "Type=" + DataTab + "&ArticleNo=" + ID; //调用文章详情的时用到的参数
        ArticleContentDTO Content = null;

        try {
            // 1. 获取唯一索引获取文章详情
            Content = articleApi.getBWArticleDetail(siteNo, DataTab, ID);
        } catch (Exception e) {
            log.error("accessParameters=" + accessParameters + "抓取失败");
            return null;
        }

        // 2. 判断数据是否存在
        // 2.1 判断是否存在爬虫库中
        String articleJsonPath = articleService.JudgeArticleStatus(Content, provenance, accessParameters);
        ArticleEnum articleStatus = articleJsonPath == null ? ArticleEnum.NOT_EXIST_ANY_DATABASE : ArticleEnum.EXIST_IN_ARTICLE;

        // 2.2 判断是否存在opencms库中
        if (StringUtils.isEmpty(articleJsonPath)) {
            articleJsonPath = articleService.queryPathInOpencms(Content, accessParameters);
            articleStatus = articleJsonPath == null ? articleStatus : ArticleEnum.EXIST_IN_TOM_ARTICLE;
        }

        // provenance 状态为2只做新增，不做更新
        if (StringUtils.isNotEmpty(articleJsonPath) && "2".equals(provenance)) {
            return "已存在";
//            throw new BizException(CommonError.INSERT_ARTICLE_EXCEPTION);
        }

        saveArticleJSON(DataTab, ID, accessParameters, articleJsonPath, Content, articleStatus);
        if ("2".equals(provenance)) {
            return "新增成功";
        }
        return "更新成功";
    }

    private void saveArticleJSON(String DataTab, String ID, String accessParameters, String articleJsonPath, ArticleContentDTO Content, ArticleEnum articleStatus) {
        //如果二级频道为空就取一级频道
        String channelID = Content.getJData().getArticle().getWebSubCategoryZeroID();
        if (StringUtil.isEmpty(channelID)) {
            channelID = Content.getJData().getArticle().getWebCategoryZeroID();
        }
        String channelname = channel.getMap().get(channelID);
        if (StringUtil.isEmpty(channelname)) {
            articleMapper.insertlog("付费文章生成json时没有找到对应的频道名称的频道id:" + channelID, ID);
            log.info("没有找到对应的频道名称的频道id:" + channelID);
            throw new BizException(CommonError.CHANNEL_NOT_FOUND);
        }

        accessParameters = "SiteNo=10&" + accessParameters;
        ArticleJSON articleJSON = articleService.createJSON(Content, channelname, accessParameters, DataTab);
        if (articleJSON == null) {
            log.error(CommonError.CAN_NOT_PRODUCE_ARTICLE_JSON.getMessage());
            return;
        }
        //转化成json格式
        String json = JSON.toJSONString(articleJSON);
        StringBuilder storePath = new StringBuilder();
        if (StringUtils.isEmpty(articleJsonPath)) {
            //新增
            //文件名(1+文章id_期刊号.json)收費文章的命名
            //查看之前的代碼，是這樣明明的，有衝突，最后决定与之前代码保持一致
            //文件名拼接
            StringBuilder fileName = new StringBuilder();
            if (!DataTab.equals("4")) {
                Long id = ((System.currentTimeMillis()) % (964000000));
                String ids = String.format("%09d", id);
                fileName.append("1").append(ids).append(".json");
            } else {
                fileName.append("1")
                        .append(Content.getJData().getArticle().getID())
                        .append("_")
                        .append(Content.getJData().getArticle().getMagazineIssueNumber())
                        .append(".json");
                final String magazineIssueNumber = Content.getJData().getArticle().getMagazineIssueNumber();
                if (StringUtils.isNotBlank(magazineIssueNumber)) {
                    // 期刊信息添加到opencms库的tom_prime_periodical表
                    articleService.insertTomPrimePeriodical(Integer.parseInt(magazineIssueNumber));
                }
            }
            //文件存放路径：/data/spiderjson/+频道名称+/content/
            storePath.append(prefix)
                    .append(channelname)
                    .append("/content/").append(fileName);
            log.info("json的保存路径:{}", storePath);
        } else {
            //更新
            storePath.append(articleJsonPath);
            log.info("json的更新路径:{}", storePath);
        }

        //保存到数据库
        int rows = 0;
        switch (articleStatus) {
            case NOT_EXIST_ANY_DATABASE:
            case EXIST_IN_TOM_ARTICLE:
                rows = articleService.insertArticle(articleJSON, Content, storePath.toString(), channelname, accessParameters, articleStatus.getCode());
                break;
            default:
                rows = articleService.updateArticle(articleJSON, Content, storePath.toString(), channelname, accessParameters, articleStatus.getCode());
                break;
        }
        if (rows < 1) {
            throw new BizException(CommonError.CAN_NOT_UPDATE_DATABASE);
        }

        try {
            FileUtils.write(new File(storePath.toString()), json, StandardCharsets.UTF_8);
            articleMapper.insertlog("成功产生的json目录：" + storePath, ID);
        } catch (IOException e) {
            log.error(CommonError.CAN_NOT_PRODUCE_ARTICLE_JSON.getMessage());
        }
    }

}
